<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        
    </style>
</head>
<body>

    <div class="box">
        <span>name：{{ name }}-{{ name }}</span><br>
        <span>age：{{ age }}-{{name}}</span><br>
        <span>sex：{{sex}}-{{name}}</span><br>
        <span>msg：{{msg}}</span><br>
        <span>msg：{{abc}}</span><br>
    </div>
    
</body>
<script>

    const vm = myVue({
        el:".box",
        data:{
            name:"admin",
            age:18,
            sex:"男",
            msg:"hello",
            abc:123123
        }
    })
    // vm.name = "root";

    function myVue(ops){
        // 处理默认参数
        ops.data = ops.data || {};
        // 获取要操作的DOM元素
        const el = document.querySelector(ops.el);
        // 保存初始DOM元素的内容
        let str = el.innerHTML;

        // 劫持对象
        const target = new Proxy(ops.data, {
            // 添加访问器
            get(origin, attr){
                return origin[attr];
            },
            // 添加控制器
            set(origin, attr, val){
                origin[attr] = val;
                // 根据最新数据，和DOM的初始内容，重新渲染DOM
                render(origin, str);
            }
        });

        function render(target, str){
            // 从DOM的初始内容中获取所有需要被渲染的标志
            const searchStr = str.match(/{{\s*[_$a-z][a-z\d_$]*\s*}}/g);
            // 遍历所有需要被渲染的标志
            searchStr.forEach(val=>{
                // 去除标志符，取出数据名
                const attr = val.match(/[^{\s}]+/)[0];
                // 替换DOM初始内容：根据要被渲染的标志，替换成数据名对应的对象属性
                str = str.replace( val,  target[attr])
            })
            // 重新设置DOM内容
            el.innerHTML = str;
        }
        // 初始渲染DOM
        render(target, str);

        // 返回劫持之后的对象，方便外部做出调整
        return target;
    }

</script>
</html>